home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / gqbist.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-22  |  18.2 KB  |  713 lines

  1. /*
  2.  * Written 1997 Jens Ch. Restemeier <jchrr@hrz.uni-bielefeld.de>
  3.  * This program is based on an algorithm / article by
  4.  * Jˆrn Loviscach.
  5.  *
  6.  * It appeared in c't 10/95, page 326 and is called 
  7.  * "Ausgew¸rfelt - Moderne Kunst algorithmisch erzeugen".
  8.  * (~modern art created with algorithms)
  9.  * 
  10.  * It generates one main formula (the middle button) and 8 variations of it.
  11.  * If you select a variation it becomes the new main formula. If you
  12.  * press "OK" the main formula will be applied to the image.
  13.  *
  14.  * This program is free software; you can redistribute it and/or modify
  15.  * it under the terms of the GNU General Public License as published by
  16.  * the Free Software Foundation; either version 2 of the License, or
  17.  * (at your option) any later version.
  18.  *
  19.  * This program is distributed in the hope that it will be useful, 
  20.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.  * GNU General Public License for more details.
  23.  *
  24.  * You should have received a copy of the GNU General Public License
  25.  * along with this program; if not, write to the Free Software
  26.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  27.  *
  28.  */
  29.  
  30. /*
  31.  * History:
  32.  * 1.0 first release
  33.  * 1.2 now handles RGB*
  34.  * 1.5 fixed a small bug
  35.  * 1.6 fixed a bug that was added by v1.5 :-(
  36.  * 1.7 added patch from Art Haas to make it compile with HP-UX, a small clean-up
  37.  * 1.8 Dscho added transform file load/save, bug-fixes 
  38.  * 1.9 rewrote renderloop.
  39.  * 1.9a fixed a bug.
  40.  * 1.9b fixed MAIN()
  41.  * 1.10 added optimizer
  42.  */
  43.                  
  44. #include "config.h"
  45.  
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <time.h>
  50.  
  51. #include <gtk/gtk.h>
  52.  
  53. #include <libgimp/gimp.h>
  54. #include <libgimp/gimpui.h>
  55.  
  56. #include "libgimp/stdplugins-intl.h"
  57.  
  58.  
  59. /** qbist renderer ***********************************************************/
  60.  
  61. #define MAX_TRANSFORMS    36
  62. #define NUM_TRANSFORMS    9
  63. #define NUM_REGISTERS    6
  64.  
  65. #define PLUG_IN_NAME "plug_in_qbist"
  66. #define PLUG_IN_VERSION "March 1998, 1.10"
  67. #define PREVIEW_SIZE 64
  68.  
  69. /** types *******************************************************************/
  70.  
  71. typedef gfloat vreg[3];
  72.  
  73. typedef struct _info
  74. {
  75.   gint transformSequence    [MAX_TRANSFORMS];
  76.   gint source        [MAX_TRANSFORMS];
  77.   gint control        [MAX_TRANSFORMS];
  78.   gint dest        [MAX_TRANSFORMS];
  79. } s_info;
  80.  
  81. #define PROJECTION    0
  82. #define SHIFT        1
  83. #define SHIFTBACK    2
  84. #define ROTATE        3
  85. #define ROTATE2        4
  86. #define MULTIPLY    5
  87. #define SINE        6
  88. #define CONDITIONAL    7
  89. #define COMPLEMENT    8
  90.  
  91. /** prototypes **************************************************************/
  92.  
  93. static void query (void);
  94. static void run   (gchar   *name,
  95.            gint     nparams,
  96.            GimpParam  *param,
  97.            gint    *nreturn_vals,
  98.            GimpParam **return_vals);
  99.  
  100. static gint dialog_create          (void);
  101. static void dialog_new_variations  (GtkWidget *widget,
  102.                     gpointer   data);
  103. static void dialog_update_previews (GtkWidget *widget,
  104.                     gpointer   data);
  105. static void dialog_select_preview  (GtkWidget *widget,
  106.                     s_info    *n_info);
  107.  
  108. static s_info qbist_info;
  109.  
  110. /** qbist functions *********************************************************/
  111.  
  112. static void
  113. create_info (s_info *info)
  114. {
  115.   int k;
  116.   for (k=0; k<MAX_TRANSFORMS; k++)
  117.     {
  118.       info->transformSequence[k]=rand() % NUM_TRANSFORMS;
  119.       info->source[k]=rand() % NUM_REGISTERS;
  120.       info->control[k]=rand() % NUM_REGISTERS;
  121.       info->dest[k]=rand() % NUM_REGISTERS;
  122.     }
  123.   info->dest[rand() % MAX_TRANSFORMS]=0;
  124. }
  125.  
  126. static void
  127. modify_info (s_info *o_info,
  128.          s_info *n_info)
  129. {
  130.   int k, n; 
  131.   memcpy(n_info, o_info, sizeof(s_info)); 
  132.   n=rand() % MAX_TRANSFORMS;
  133.   for (k=0;k<n; k++)
  134.     {
  135.       switch (rand() % 4)
  136.     {
  137.     case 0: n_info->transformSequence[rand() % MAX_TRANSFORMS] = rand() % NUM_TRANSFORMS; break;
  138.     case 1: n_info->source[rand() % MAX_TRANSFORMS]            = rand() % NUM_REGISTERS; break;
  139.     case 2: n_info->control[rand() % MAX_TRANSFORMS]           = rand() % NUM_REGISTERS; break;
  140.     case 3: n_info->dest[rand() % MAX_TRANSFORMS]              = rand() % NUM_REGISTERS; break;
  141.     }
  142.     }
  143. }
  144.  
  145. /*
  146.  * Optimizer
  147.  */
  148. static gint used_trans_flag[MAX_TRANSFORMS];
  149. static gint used_reg_flag[NUM_REGISTERS];
  150.  
  151. static void
  152. check_last_modified (s_info info,
  153.              int    p,
  154.              int    n)
  155. {
  156.   p--;
  157.   while ((p>=0) && (info.dest[p]!=n)) p--;
  158.   if (p<0) 
  159.     used_reg_flag[n]=1;
  160.   else
  161.     {
  162.       used_trans_flag[p]=1;
  163.       check_last_modified(info, p, info.source[p]);
  164.       check_last_modified(info, p, info.control[p]);
  165.     }
  166. }
  167.  
  168. static void
  169. optimize (s_info info)
  170. {
  171.   int i;
  172.   /* double-arg fix: */
  173.   for (i=0; i<MAX_TRANSFORMS; i++)
  174.     {
  175.       used_trans_flag[i]=0;
  176.       if (i<NUM_REGISTERS)
  177.     used_reg_flag[i]=0;
  178.       /* double-arg fix: */
  179.       switch (info.transformSequence[i])
  180.     {
  181.     case ROTATE: 
  182.     case ROTATE2: 
  183.     case COMPLEMENT: 
  184.       info.control[i]=info.dest[i];
  185.       break;
  186.     }
  187.     }
  188.   /* check for last modified item */
  189.   check_last_modified(info, MAX_TRANSFORMS, 0);
  190. }
  191.  
  192. static void
  193. qbist (s_info  info,
  194.        gchar  *buffer,
  195.        int     xp,
  196.        int     yp,
  197.        int     num,
  198.        int     width,
  199.        int     height,
  200.        int     bpp)
  201. {
  202.   gushort gx;
  203.   vreg reg [NUM_REGISTERS];
  204.   int i;
  205.   gushort sr, cr, dr;
  206.  
  207.   if (num<=0) return;
  208.  
  209.   for(gx=0; gx<num; gx ++)
  210.     {
  211.       for(i=0; i<NUM_REGISTERS; i++)
  212.     {
  213.       if (used_reg_flag[i])
  214.         {
  215.           reg[i][0] = ((float)gx+xp) / ((float)(width));
  216.           reg[i][1] = ((float)yp) / ((float)(height));
  217.           reg[i][2] = ((float)i) / ((float)NUM_REGISTERS);
  218.         }
  219.     }
  220.       for(i=0;i<MAX_TRANSFORMS; i++)
  221.     {
  222.       sr=info.source[i];cr=info.control[i];dr=info.dest[i];
  223.  
  224.       if (used_trans_flag[i]) switch (info.transformSequence[i])
  225.         {
  226.         case PROJECTION:
  227.           {
  228.         gfloat scalarProd;
  229.         scalarProd = (reg[sr][0]*reg[cr][0])+(reg[sr][1]*reg[cr][1])+(reg[sr][2]*reg[cr][2]);
  230.         reg[dr][0] = scalarProd*reg[sr][0];
  231.         reg[dr][1] = scalarProd*reg[sr][1];
  232.         reg[dr][2] = scalarProd*reg[sr][2];
  233.         break;
  234.           }
  235.         case SHIFT: 
  236.           reg[dr][0] = reg[sr][0]+reg[cr][0];
  237.           if (reg[dr][0] >= 1.0) reg[dr][0] -= 1.0;
  238.           reg[dr][1] = reg[sr][1]+reg[cr][1];
  239.           if (reg[dr][1] >= 1.0) reg[dr][1] -= 1.0;
  240.           reg[dr][2] = reg[sr][2]+reg[cr][2];
  241.           if (reg[dr][2] >= 1.0) reg[dr][2] -= 1.0;
  242.           break;
  243.         case SHIFTBACK: 
  244.           reg[dr][0] = reg[sr][0]-reg[cr][0];
  245.           if (reg[dr][0] <= 0.0) reg[dr][0] += 1.0;
  246.           reg[dr][1] = reg[sr][1]-reg[cr][1];
  247.           if (reg[dr][1] <= 0.0) reg[dr][1] += 1.0;
  248.           reg[dr][2] = reg[sr][2]-reg[cr][2];
  249.           if (reg[dr][2] <= 0.0) reg[dr][2] += 1.0;
  250.           break;
  251.         case ROTATE: 
  252.           reg[dr][0] = reg[sr][1];
  253.           reg[dr][1] = reg[sr][2];
  254.           reg[dr][2] = reg[sr][0];
  255.           break;
  256.         case ROTATE2: 
  257.           reg[dr][0] = reg[sr][2];
  258.           reg[dr][1] = reg[sr][0];
  259.           reg[dr][2] = reg[sr][1];
  260.           break;
  261.         case MULTIPLY: 
  262.           reg[dr][0] = reg[sr][0]*reg[cr][0];
  263.           reg[dr][1] = reg[sr][1]*reg[cr][1];
  264.           reg[dr][2] = reg[sr][2]*reg[cr][2];
  265.           break;
  266.         case SINE: 
  267.           reg[dr][0] = 0.5+(0.5*sin(20.0*reg[sr][0]*reg[cr][0]));
  268.           reg[dr][1] = 0.5+(0.5*sin(20.0*reg[sr][1]*reg[cr][1]));
  269.           reg[dr][2] = 0.5+(0.5*sin(20.0*reg[sr][2]*reg[cr][2]));
  270.           break;
  271.         case CONDITIONAL: 
  272.           if ((reg[cr][0]+reg[cr][1]+reg[cr][2]) > 0.5)
  273.         {
  274.           reg[dr][0] = reg[sr][0];
  275.           reg[dr][1] = reg[sr][1];
  276.           reg[dr][2] = reg[sr][2];
  277.         }
  278.           else
  279.         {
  280.           reg[dr][0] = reg[cr][0];
  281.           reg[dr][1] = reg[cr][1];
  282.           reg[dr][2] = reg[cr][2];
  283.         }
  284.           break;
  285.         case COMPLEMENT: 
  286.           reg[dr][0] = 1.0-reg[sr][0];
  287.           reg[dr][1] = 1.0-reg[sr][1];
  288.           reg[dr][2] = 1.0-reg[sr][2];
  289.           break;
  290.         }
  291.     }
  292.       for (i=0; i<bpp; i++)
  293.     {
  294.       if (i<3)
  295.         { 
  296.           int a;
  297.           a=255.0 * reg[0][i];
  298.           buffer[i]=(a<0) ? 0 : ((a>255) ? 255 : a); 
  299.         }
  300.       else
  301.         {
  302.           buffer[i]=255;
  303.         }
  304.     }
  305.       buffer+=bpp;
  306.     }
  307. }
  308.  
  309. /** Plugin interface *********************************************************/
  310.  
  311. GimpPlugInInfo PLUG_IN_INFO =
  312. {
  313.   NULL,     /* init_proc  */
  314.   NULL,     /* quit_proc  */
  315.   query, /* query_proc */
  316.   run     /* run_proc   */
  317. };
  318.  
  319. MAIN ()
  320.  
  321. static void
  322. query (void)
  323. {
  324.   GimpParamDef args[] =
  325.   {
  326.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  327.     { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
  328.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
  329.   };
  330.   gint nargs = sizeof (args) / sizeof (args[0]);
  331.  
  332.   gimp_install_procedure (PLUG_IN_NAME,
  333.               "Create images based on a random genetic formula",
  334.               "This Plug-in is based on an article by Jˆrn Loviscach (appeared in c't 10/95, page 326). It generates modern art pictures from a random genetic formula.",
  335.               "Jˆrn Loviscach, Jens Ch. Restemeier",
  336.               "Jˆrn Loviscach, Jens Ch. Restemeier",
  337.               PLUG_IN_VERSION,
  338.               N_("<Image>/Filters/Render/Pattern/Qbist..."),
  339.               "RGB*",
  340.               GIMP_PLUGIN,
  341.               nargs, 0,
  342.               args, NULL);
  343. }
  344.  
  345. static void
  346. run (gchar   *name,
  347.      gint     nparams,
  348.      GimpParam  *param,
  349.      gint    *nreturn_vals,
  350.      GimpParam **return_vals)
  351. {
  352.   static GimpParam values[1];
  353.   gint sel_x1, sel_y1, sel_x2, sel_y2;
  354.   gint img_height, img_width, img_bpp, img_has_alpha;
  355.  
  356.   GimpDrawable     *drawable;
  357.   GimpRunModeType    run_mode;
  358.   GimpPDBStatusType    status;
  359.  
  360.   *nreturn_vals = 1;
  361.   *return_vals  = values;
  362.  
  363.   status = GIMP_PDB_SUCCESS;
  364.  
  365.   if (param[0].type!=GIMP_PDB_INT32)
  366.     status=GIMP_PDB_CALLING_ERROR;
  367.   run_mode = param[0].data.d_int32;
  368.  
  369.   if (run_mode == GIMP_RUN_INTERACTIVE)
  370.     {
  371.       INIT_I18N_UI();
  372.     }
  373.   else
  374.     {
  375.       INIT_I18N();
  376.     }
  377.  
  378.   if (param[2].type!=GIMP_PDB_DRAWABLE)
  379.     status=GIMP_PDB_CALLING_ERROR;
  380.   drawable = gimp_drawable_get(param[2].data.d_drawable);
  381.  
  382.   img_width     = gimp_drawable_width(drawable->id);
  383.   img_height    = gimp_drawable_height(drawable->id);
  384.   img_bpp       = gimp_drawable_bpp(drawable->id);
  385.   img_has_alpha = gimp_drawable_has_alpha(drawable->id);
  386.   gimp_drawable_mask_bounds (drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
  387.  
  388.   if (!gimp_drawable_is_rgb(drawable->id))
  389.     status=GIMP_PDB_CALLING_ERROR;
  390.         
  391.   if (status==GIMP_PDB_SUCCESS)
  392.     {
  393.       create_info(&qbist_info);
  394.       switch (run_mode)
  395.     {
  396.     case GIMP_RUN_INTERACTIVE:
  397.       /* Possibly retrieve data */
  398.       gimp_get_data(PLUG_IN_NAME, &qbist_info);
  399.  
  400.           /* Get information from the dialog */
  401.       if (dialog_create())
  402.         {
  403.           status=GIMP_PDB_SUCCESS;
  404.           gimp_set_data(PLUG_IN_NAME, &qbist_info, sizeof(s_info));
  405.         }
  406.       else
  407.         status=GIMP_PDB_EXECUTION_ERROR;
  408.       break;
  409.  
  410.     case GIMP_RUN_NONINTERACTIVE:
  411.       status=GIMP_PDB_CALLING_ERROR;
  412.       break;
  413.  
  414.     case GIMP_RUN_WITH_LAST_VALS:
  415.       /* Possibly retrieve data */
  416.       gimp_get_data(PLUG_IN_NAME, &qbist_info);
  417.       status=GIMP_PDB_SUCCESS;
  418.       break;
  419.     default:
  420.       status=GIMP_PDB_CALLING_ERROR;
  421.       break;
  422.     } 
  423.       if (status == GIMP_PDB_SUCCESS)
  424.     {
  425.       GimpPixelRgn imagePR;
  426.       guchar *row_data;
  427.       gint row;
  428.  
  429.       gimp_tile_cache_ntiles((drawable->width + gimp_tile_width() - 1) / gimp_tile_width());
  430.       gimp_pixel_rgn_init (&imagePR, drawable, 0,0, img_width, img_height, TRUE, TRUE);
  431.       row_data=(guchar *)malloc((sel_x2-sel_x1)*img_bpp);
  432.  
  433.       optimize(qbist_info);
  434.  
  435.       gimp_progress_init ( _("Qbist..."));
  436.       for (row=sel_y1; row<sel_y2; row++)
  437.         {
  438.           qbist(qbist_info, (gchar *)row_data, 0, row, sel_x2-sel_x1, sel_x2-sel_x1, sel_y2-sel_y1, img_bpp);
  439.           gimp_pixel_rgn_set_row(&imagePR, row_data, sel_x1, row, (sel_x2-sel_x1));
  440.           if ((row % 5) == 0) 
  441.         gimp_progress_update((gfloat)(row-sel_y1)/(gfloat)(sel_y2-sel_y1));
  442.         }
  443.  
  444.       free(row_data);
  445.       gimp_drawable_flush (drawable);
  446.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  447.       gimp_drawable_update (drawable->id, sel_x1, sel_y1, (sel_x2 - sel_x1), (sel_y2 - sel_y1));
  448.  
  449.       gimp_displays_flush();
  450.     } 
  451.     }
  452.  
  453.   values[0].type = GIMP_PDB_STATUS;
  454.   values[0].data.d_status = status;
  455.   gimp_drawable_detach(drawable);
  456. }
  457.  
  458. /** User interface ***********************************************************/
  459.  
  460. static GtkWidget *preview[9];
  461. static s_info     info[9];
  462. static gint       result = FALSE;
  463.  
  464. static void
  465. dialog_ok (GtkWidget *widget,
  466.        gpointer   data)
  467. {
  468.   result = TRUE;
  469.  
  470.   gtk_widget_destroy (GTK_WIDGET (data));
  471. }
  472.  
  473. static void
  474. dialog_new_variations (GtkWidget *widget,
  475.                gpointer data)
  476. {
  477.   gint i;
  478.  
  479.   for (i = 1; i < 9; i++)
  480.     modify_info (&(info[0]), &(info[i]));
  481. }
  482.  
  483. static void
  484. dialog_update_previews (GtkWidget *widget,
  485.             gpointer   data)
  486. {
  487.   gint i, j;
  488.   guchar buf[PREVIEW_SIZE * 3];
  489.  
  490.   for (j=0;j<9;j++)
  491.     {
  492.       optimize (info[(j+5) % 9]);
  493.       for (i = 0; i < PREVIEW_SIZE; i++)
  494.     {
  495.       qbist (info[(j+5) % 9], (gchar *)buf,
  496.          0, i, PREVIEW_SIZE, PREVIEW_SIZE, PREVIEW_SIZE, 3);
  497.       gtk_preview_draw_row (GTK_PREVIEW (preview[j]), buf,
  498.                 0, i, PREVIEW_SIZE);
  499.     }
  500.       gtk_widget_draw (preview[j], NULL);
  501.     }
  502. }
  503.  
  504. static void
  505. dialog_select_preview (GtkWidget *widget,
  506.                s_info    *n_info)
  507. {
  508.   memcpy (&(info[0]), n_info, sizeof (s_info));
  509.   dialog_new_variations (widget, NULL);
  510.   dialog_update_previews (widget, NULL);
  511. }
  512.  
  513. /* File I/O stuff */
  514.  
  515. #define LOBITE(x) ((x)&0xff)
  516. #define HIBITE(x) ((x)>>8)
  517. #define MACBITES(x) (HIBITE(x)+LOBITE(x)<<8)
  518. #define GETMACUSHORT(f) ((fgetc(f)<<8)+(fgetc(f)))
  519. #define PUTMACUSHORT(u, f) fprintf(f, "%c%c", HIBITE(u), LOBITE(u));
  520.  
  521. static gint
  522. load_data (gchar *name)
  523. {
  524.   int i;
  525.   FILE *f;
  526.  
  527.   f = fopen (name, "rb"); 
  528.   if (f==NULL) return 0;
  529.  
  530.   for (i=0;i<MAX_TRANSFORMS;i++) info[0].transformSequence[i]=GETMACUSHORT(f);
  531.   for (i=0;i<MAX_TRANSFORMS;i++) info[0].source[i]=GETMACUSHORT(f);
  532.   for (i=0;i<MAX_TRANSFORMS;i++) info[0].control[i]=GETMACUSHORT(f);
  533.   for( i=0;i<MAX_TRANSFORMS;i++) info[0].dest[i]=GETMACUSHORT(f);
  534.  
  535.   fclose (f);
  536.  
  537.   return 1;
  538. }
  539.  
  540. static void
  541. save_data (gchar *name)
  542. {
  543.   int i=0;
  544.   FILE *f;
  545.  
  546.   f = fopen (name, "wb");
  547.  
  548.   for (i=0;i<MAX_TRANSFORMS;i++) PUTMACUSHORT(info[0].transformSequence[i], f);
  549.   for (i=0;i<MAX_TRANSFORMS;i++) PUTMACUSHORT(info[0].source[i], f);
  550.   for (i=0;i<MAX_TRANSFORMS;i++) PUTMACUSHORT(info[0].control[i], f);
  551.   for (i=0;i<MAX_TRANSFORMS;i++) PUTMACUSHORT(info[0].dest[i], f);
  552.  
  553.   fclose (f);
  554. }
  555.  
  556. static void
  557. file_selection_save (GtkWidget *widget,
  558.              GtkWidget *file_select)
  559. {
  560.   save_data (gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_select)));
  561.   gtk_widget_destroy (file_select);
  562. }
  563.  
  564. static void
  565. file_selection_load (GtkWidget *widget,
  566.              GtkWidget *file_select)
  567. {
  568.   load_data (gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_select)));
  569.   gtk_widget_destroy (file_select);
  570.   dialog_new_variations (widget, NULL);
  571.   dialog_update_previews (widget, NULL);
  572. }
  573.  
  574. static void
  575. dialog_load (GtkWidget *widget,
  576.          gpointer   data)
  577. {
  578.   GtkWidget *file_select;
  579.  
  580.   file_select = gtk_file_selection_new (_("Load QBE file..."));
  581.  
  582.   gimp_help_connect_help_accel (file_select, gimp_standard_help_func,
  583.                 "filters/gqbist.html");
  584.  
  585.   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_select)->ok_button), 
  586.               "clicked",
  587.               GTK_SIGNAL_FUNC (file_selection_load),
  588.               (gpointer) file_select);
  589.   gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (file_select)->cancel_button),
  590.                  "clicked",
  591.                  GTK_SIGNAL_FUNC (gtk_widget_destroy),
  592.                  GTK_OBJECT (file_select));
  593.  
  594.   gtk_widget_show (file_select);
  595. }
  596.  
  597. static void
  598. dialog_save (GtkWidget *widget,
  599.          gpointer   data)
  600. {
  601.   GtkWidget *file_select;
  602.  
  603.   file_select =
  604.     gtk_file_selection_new (_("Save (middle transform) as QBE file..."));
  605.  
  606.   gimp_help_connect_help_accel (file_select, gimp_standard_help_func,
  607.                 "filters/gqbist.html");
  608.  
  609.   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_select)->ok_button),
  610.               "clicked",
  611.               GTK_SIGNAL_FUNC (file_selection_save),
  612.               (gpointer)file_select);
  613.   gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (file_select)->cancel_button), 
  614.                  "clicked",
  615.                  GTK_SIGNAL_FUNC (gtk_widget_destroy),
  616.                  GTK_OBJECT (file_select));
  617.  
  618.   gtk_widget_show (file_select);
  619. }
  620.  
  621. static gint
  622. dialog_create (void)
  623. {
  624.   GtkWidget *dialog;
  625.   GtkWidget *vbox;
  626.   GtkWidget *bbox;
  627.   GtkWidget *button;
  628.   GtkWidget *table;
  629.   gint  i;
  630.  
  631.   srand (time (NULL));
  632.  
  633.   gimp_ui_init ("gqbist", TRUE);
  634.  
  635.   dialog = gimp_dialog_new (_("G-Qbist 1.10"), "gqbist",
  636.                 gimp_standard_help_func, "filters/gqbist.html",
  637.                 GTK_WIN_POS_MOUSE,
  638.                 FALSE, TRUE, FALSE,
  639.  
  640.                 _("OK"), dialog_ok,
  641.                 NULL, NULL, NULL, TRUE, FALSE,
  642.                 _("Cancel"), gtk_widget_destroy,
  643.                 NULL, 1, NULL, FALSE, TRUE,
  644.  
  645.                 NULL);
  646.  
  647.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy", 
  648.               GTK_SIGNAL_FUNC (gtk_main_quit),
  649.               NULL);
  650.  
  651.   vbox = gtk_vbox_new (FALSE, 6);
  652.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
  653.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox,
  654.               FALSE, FALSE, 0);
  655.   gtk_widget_show (vbox);
  656.  
  657.   table = gtk_table_new (3, 3, FALSE);
  658.   gtk_table_set_row_spacings (GTK_TABLE (table), 5);
  659.   gtk_table_set_col_spacings (GTK_TABLE (table), 5);
  660.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  661.   gtk_widget_show (table);
  662.  
  663.   memcpy ((char *) &(info[0]), (char *) &qbist_info, sizeof (s_info));
  664.   dialog_new_variations (NULL, NULL);
  665.  
  666.   for (i = 0; i < 9; i++)
  667.     {
  668.       button = gtk_button_new ();
  669.       gtk_signal_connect (GTK_OBJECT (button), "clicked", 
  670.               GTK_SIGNAL_FUNC (dialog_select_preview),
  671.               (gpointer) &(info[(i+5)%9]));
  672.       gtk_table_attach (GTK_TABLE (table), button, i%3, (i%3)+1, i/3, (i/3)+1, 
  673.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  674.       gtk_widget_show (button);
  675.  
  676.       preview[i] = gtk_preview_new (GTK_PREVIEW_COLOR);
  677.       gtk_preview_size (GTK_PREVIEW (preview[i]), PREVIEW_SIZE, PREVIEW_SIZE);
  678.       gtk_container_add (GTK_CONTAINER (button), preview[i]);
  679.       gtk_widget_show (preview[i]);
  680.     }
  681.  
  682.   bbox = gtk_hbutton_box_new ();
  683.   gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
  684.   gtk_widget_show (bbox);
  685.  
  686.   button = gtk_button_new_with_label (_("Load"));
  687.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  688.   gtk_container_add (GTK_CONTAINER (bbox), button);
  689.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  690.               GTK_SIGNAL_FUNC (dialog_load),
  691.               NULL);
  692.   gtk_widget_show (button);
  693.  
  694.   button = gtk_button_new_with_label (_("Save"));
  695.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  696.   gtk_container_add (GTK_CONTAINER (bbox), button);
  697.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  698.               GTK_SIGNAL_FUNC (dialog_save),
  699.               NULL);
  700.   gtk_widget_show (button);
  701.  
  702.   dialog_update_previews (NULL, NULL);
  703.   gtk_widget_show (dialog);
  704.  
  705.   gtk_main ();
  706.   gdk_flush ();
  707.  
  708.   if (result)
  709.     memcpy ((char *) &qbist_info, (char *) &(info[0]), sizeof (s_info));
  710.  
  711.   return result;
  712. }
  713.